using System;
using System.Collections.Generic;
using System.Diagnostics.SymbolStore;
using System.Runtime.InteropServices;
using System.Text;
using ACS.Debugger.Core.Impl;
using ACS.Debugger.Core.Interfaces;
using ACS.Debugger.Core.NativeMethods;

namespace ACS.Tests
{
    class Program
    {
        private enum CreateProcessFlags 
        {
            CREATE_NEW_CONSOLE = 0x00000010,
            DEBUG_PROCESS = 3, //DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS
        }

        static void Main(string[] args)
        {
            ICorDebug debug = Debugging.GetDebugger();
            debug.Initialize();

            PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

            STARTUPINFO si = new STARTUPINFO();
            si.cb = Marshal.SizeOf(si);

            // initialize safe handles 
            si.hStdInput = new Microsoft.Win32.SafeHandles.SafeFileHandle(new IntPtr(0), false);
            si.hStdOutput = new Microsoft.Win32.SafeHandles.SafeFileHandle(new IntPtr(0), false);
            si.hStdError = new Microsoft.Win32.SafeHandles.SafeFileHandle(new IntPtr(0), false);            


            M m = new M();
            
            debug.SetManagedHandler(m);
            System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                
                debug.CreateProcess(
                          @"C:\kurs\ACS.SampleCode\bin\Debug\acs.samplecode.exe", //lpApplicationName,
                          @"C:\kurs\ACS.SampleCode\bin\Debug\acs.samplecode.exe", //lpCommandLine,
                          null, //lpProcessAttributes,
                          null, //lpThreadAttributes,
                          1, //bInheritHandles,
                          (uint) 0,//CreateProcessFlags.CREATE_NEW_CONSOLE, //dwCreationFlags,
                          new IntPtr(0), //lpEnvironment,
                          @"C:\kurs\ACS.SampleCode\bin\Debug",
                          si, //lpStartupInfo,
                          pi, //lpProcessInformation,
                          CorDebugCreateProcessFlags.DEBUG_NO_SPECIAL_OPTIONS,
                          out m.process
                );
                Debugging.CloseHandle(pi.hProcess);
                Debugging.CloseHandle(pi.hThread);


            } catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
            }

            B Mybr = new B();
         
            LT crbr = new LT();
            crbr.BF();
            //ICorDebugThread ppThread ;
            //ICorDebugAppDomain pDom = null;
            
            //m.CreateAppDomain(m.process, pDom);
            //m.CreateThread(pDom, ppThread);
            //m.Breakpoint(null, ppThread, Mybr);
            
            while(true)
            {
            }
        }
    }



    public class M : ICorDebugManagedCallback, ICorDebugManagedCallback2
    {
        public ICorDebugProcess process;
        public ICorDebugFunctionBreakpoint funcbr;
       
        public void Breakpoint(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, ICorDebugBreakpoint pBreakpoint)
        {
             uint offset = 0;
            //long hr;
            process.SetThreadContext(0u, 0u, new IntPtr());
            //process.SetAllThreadsDebugState(CorDebugThreadState.THREAD_RUN, pThread);
          //  pBreakpoint.Activate(0);
            
            funcbr.GetOffset(out offset); 
            Console.WriteLine(offset);
            //pBreakpoint.IsActive(out i);
            //Console.WriteLine(i);
            process.Continue(0);
        }

        public void StepComplete(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, ICorDebugStepper pStepper,
                                 CorDebugStepReason reason)
        {
            process.Continue(0);
             
        }

        public void Break(ICorDebugAppDomain pAppDomain, ICorDebugThread thread)
        { 
            process.Continue(0);
             
        }

        public void Exception(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, int unhandled)
        {
            process.Continue(0);
             
        }

        public void EvalComplete(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, ICorDebugEval pEval)
        {
            process.Continue(0);
             
        }

        public void EvalException(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, ICorDebugEval pEval)
        { 
            process.Continue(0);
             
        }

        public void CreateProcess(ICorDebugProcess pProcess)
        {
            Console.WriteLine("before stop");
            process.Stop(100);
            Console.WriteLine("we're here");
            process.Continue(0);
        }

        public void ExitProcess(ICorDebugProcess pProcess)
        { 
            process.Continue(0);
             
        }

        public void CreateThread(ICorDebugAppDomain pAppDomain, ICorDebugThread thread)
        {
            Console.WriteLine("creating thread");
            process.Continue(0);
             
        }

        public void ExitThread(ICorDebugAppDomain pAppDomain, ICorDebugThread thread)
        {
            process.Continue(0);
             
        }

        public void LoadModule(ICorDebugAppDomain pAppDomain, ICorDebugModule pModule)
        { 
            process.Continue(0);

        }

        public void UnloadModule(ICorDebugAppDomain pAppDomain, ICorDebugModule pModule)
        {
            process.Continue(0);
             
        }

        public void LoadClass(ICorDebugAppDomain pAppDomain, ICorDebugClass c)
        { 
            process.Continue(0);
             
        }

        public void UnloadClass(ICorDebugAppDomain pAppDomain, ICorDebugClass c)
        {
            process.Continue(0);
             
        }

        public void DebuggerError(ICorDebugProcess pProcess, int errorHR, uint errorCode)
        {
            process.Continue(0);
             
        }

        public void LogMessage(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, int lLevel,
                               ref ushort pLogSwitchName, ref ushort pMessage)
        { 
            process.Continue(0);
             
        }

        public void LogSwitch(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, int lLevel, uint ulReason,
                              ref ushort pLogSwitchName, ref ushort pParentName)
        {
            process.Continue(0);
             
        }

        public void CreateAppDomain(ICorDebugProcess pProcess, ICorDebugAppDomain pAppDomain)
        {
            pAppDomain.Attach();
            process.Continue(0);
             
        }

        public void ExitAppDomain(ICorDebugProcess pProcess, ICorDebugAppDomain pAppDomain)
        { 
            process.Continue(0);
             
        }

        public void LoadAssembly(ICorDebugAppDomain pAppDomain, ICorDebugAssembly pAssembly)
        {
            process.Continue(0);
             
        }

        public void UnloadAssembly(ICorDebugAppDomain pAppDomain, ICorDebugAssembly pAssembly)
        {
            process.Continue(0);
             
        }

        public void ControlCTrap(ICorDebugProcess pProcess)
        {
            process.Continue(0);
             
        }

        public void NameChange(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread)
        { 
            process.Continue(0);
             
        }

        public void UpdateModuleSymbols(ICorDebugAppDomain pAppDomain, ICorDebugModule pModule, IStream pSymbolStream)
        {
            process.Continue(0);
             
        }

        public void EditAndContinueRemap(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread,
                                         ICorDebugFunction pFunction, int fAccurate)
        { 
            process.Continue(0);
             
        }

        public void BreakpointSetError(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread,
                                       ICorDebugBreakpoint pBreakpoint, uint dwError)
        { 
            process.Continue(0);
             
        }

        public void FunctionRemapOpportunity(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread,
                                             ICorDebugFunction pOldFunction, ICorDebugFunction pNewFunction,
                                             uint oldILOffset)
        { 
            process.Continue(0);
            
        }

        public void CreateConnection(ICorDebugProcess pProcess, uint dwConnectionId, ref ushort pConnName)
        {
            process.Continue(0);

        }

        public void ChangeConnection(ICorDebugProcess pProcess, uint dwConnectionId)
        {
            process.Continue(0);
        }

        public void DestroyConnection(ICorDebugProcess pProcess, uint dwConnectionId)
        {
            process.Continue(0);

        }

        public void Exception(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, ICorDebugFrame pFrame,
                              uint nOffset, CorDebugExceptionCallbackType dwEventType, uint dwFlags)
        {
            process.Continue(0);

        }

        public void ExceptionUnwind(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread,
                                    CorDebugExceptionUnwindCallbackType dwEventType, uint dwFlags)
        {
            process.Continue(0);

        }

        public void FunctionRemapComplete(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread,
                                          ICorDebugFunction pFunction)
        {
            process.Continue(0);

        }

        public void MDANotification(ICorDebugController pController, ICorDebugThread pThread, ICorDebugMDA pMDA)
        { 
            process.Continue(0);

        }
    }

    public class B : ICorDebugBreakpoint
    {
        public void Activate(int bActive)
        {
            Console.WriteLine("v activatete");
            // throw new NotImplementedException();
        }

        public void IsActive(out int pbActive)
        {
            pbActive = 1;
            //throw new NotImplementedException();
        }
    }

   public class LT
   {
       public ICorDebugModule m_modulebd;//how to initialize?
       public ISymbolBinder1 m_binder;
       public char[] moduleName = new char[256];
       uint numberCharac;
       public IntPtr metadata = new IntPtr();
       public ISymbolReader m_reader;
       public ISymbolDocument sourcedocument;
       public ISymbolMethod breakpointMethod;
       private int myline = 0;//what value???
       private int sequencePointOffset;
       public SymbolToken methodToken;
       public ICorDebugFunction runTimeFunction;
       public ICorDebugCode functionCode;
       public ICorDebugFunctionBreakpoint breakpoint; 

       public void BF()
       {
           m_modulebd.GetName((uint) moduleName.GetLength(0), out numberCharac, moduleName);

           m_binder.GetReader(metadata, moduleName.ToString(), "");

           m_reader.GetDocuments();
           breakpointMethod = m_reader.GetMethodFromDocumentPosition(sourcedocument, myline, 1);
           sequencePointOffset = breakpointMethod.GetOffset(sourcedocument, myline, 1);
           methodToken = breakpointMethod.Token;

           m_modulebd.GetFunctionFromToken(methodToken, out runTimeFunction);
           
           runTimeFunction.GetILCode(out functionCode);
           functionCode.CreateBreakpoint((uint) sequencePointOffset, out breakpoint);
       }
   }
    
}
